﻿using System.Security.Claims;
using System.Text.RegularExpressions;
using K9Nano.Application.Dtos;
using K9Nano.AspNetCore.Security;
using K9Nano.Captcha.Sms;
using K9Nano.Domain.Authentication;
using K9Nano.Domain.Entities;
using K9Nano.Exceptions;
using K9Nano.GlobalOptions;
using Microsoft.AspNetCore.Mvc;

namespace K9Nano.AspNetCore.Controllers;

[Produces("application/json")]
[ApiController]
public abstract class TokenControllerBase<TUser, TRole, TUserManager>(TUserManager userManager,
    ISmsCaptchaManager smsCaptchaManager,
    IJwtHelper jwtHelper)
    : ControllerBase
    where TUser : UserBase
    where TRole : RoleBase
    where TUserManager : IUserManager<TUser, TRole>
{
    [HttpPost("login")]
    public virtual async Task<JwtResponse?> Login(JwtTokenDto dto)
    {
        var user = await userManager.FindByPasswordAsync(dto.Username, dto.Password, HttpContext.RequestAborted)
            ?? throw FriendlyException.BadRequest("用户名或者密码错误");
        var roles = await userManager.GetRolesAsync(user.Id, HttpContext.RequestAborted);
        var token = jwtHelper.GenerateJwtToken(
            roles.Select(a => new Claim(ClaimTypes.Role, a)).ToArray()
            .Concat
            (
                [
                new Claim(ClaimTypes.Name, user.Username),
                new Claim(ClaimTypes.Sid, user.Id.ToString()!)
                ]
            ));
        return token;
    }

    /// <summary>
    /// 手机号通过短信验证码登录
    /// </summary>
    /// <param name="phone">手机号</param>
    /// <param name="code">短信验证码</param>
    /// <returns></returns>
    [HttpPost("login/phone/{phone:required}/code/{code:required}")]
    public JwtResponse LoginAsPhone(string phone, string code)
    {
        if (!Regex.IsMatch(phone, RegexPatterns.Phone))
        {
            throw FriendlyException.BadRequest("手机号格式错误");
        }
        if (!smsCaptchaManager.Validate(phone, code))
        {
            throw FriendlyException.BadRequest("短信验证码错误");
        }

        var claims = new List<Claim>
        {
            new(ClaimTypes.Name, phone),
            new(ClaimTypes.MobilePhone, phone)
        };
        var token = jwtHelper.GenerateJwtToken(claims);
        return token;
    }

    [HttpGet("test")]
    public bool Test()
    {
        var headerVal = Request.Headers.Authorization.FirstOrDefault();
        if (string.IsNullOrEmpty(headerVal))
        {
            return false;
        }
        if(!headerVal.StartsWith("Bearer ", StringComparison.Ordinal))
        {
            return false;   
        }
        return jwtHelper.Test(headerVal[7..]);
    }
}